package shm;

import org.apache.tomcat.jni.Global;
import org.apache.tomcat.jni.Lock;
import org.apache.tomcat.jni.Pool;
import org.apache.tomcat.jni.Shm;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Date;
import java.util.Properties;
import java.util.Random;

/**
 * License: Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html)
 * <p/>
 * Author: Ashwin Jayaprakash
 * <p/>
 * Email: ashwin.jayaprakash@gmail.com
 * <p/>
 * Web: http://www.ashwinjayaprakash.com
 */
public class ShmWriter extends ShmCommon {
    public ShmWriter() {
    }

    public void test(Properties properties) throws Exception {
        long poolHandle = Pool.create(0);
        sout("Created Pool " + poolHandle);

        long shmHandle = Shm.create(4096, NAME_SHM, poolHandle);
        sout("Created Shm " + NAME_SHM);

        long mutexHandle = Global.create(NAME_MUTEX, Lock.APR_LOCK_FCNTL, poolHandle);
        sout("Created Mutex " + NAME_MUTEX);

        sout("Locking Mutex " + mutexHandle);
        int lockStatus = Global.lock(mutexHandle);
        sout("Locked Mutex " + mutexHandle + " @ " + new Date());

        long childProcHandle = -1;

        try {
            String progName = properties.getProperty("progName");
            String progArgsCombined = properties.getProperty("progArgs");
            String[] progArgs =
                    (progArgsCombined != null && progArgsCombined.length() > 0) ? progArgsCombined.split(" ") : null;
            if (progArgs != null) {
                String[] x = new String[progArgs.length + 1];
                x[0] = "";
                for (int i = 0; i < progArgs.length; i++) {
                    x[i + 1] = progArgs[i];
                }
                progArgs = x;
            }
            String progDir = properties.getProperty("progDir");

            sout(String.format("Launching child [%s] [%s] [%s]...%n", progName, progArgsCombined, progDir));

            childProcHandle = ProcCommon.launchChildProcess(poolHandle, progName, progArgs, null, progDir);

            sout("Launched child");

            //---------------

            sout("Sleeping for 30 secs @ " + new Date());
            Thread.sleep(30000);
            sout("Woke up @ " + new Date());

            ByteBuffer bb = Shm.buffer(shmHandle);
            sout(bb.toString());

            String message = "Hello world " + new Random().nextInt(999) + "!";
            bb.putInt(message.length());

            CharBuffer cb = bb.asCharBuffer();
            cb.append(message);
            sout("Wrote message [" + message + "] to Shm " + shmHandle);
        }
        finally {
            try {
                Global.unlock(mutexHandle);
                sout("Unlocked Mutex " + mutexHandle + " @ " + new Date());

                //---------------

                sout("Waiting for child...");
                ProcCommon.waitForChildProcess(childProcHandle);
            }
            finally {
                Shm.destroy(shmHandle);
                sout("Released Shm " + shmHandle + " @ " + new Date());
            }
        }

        sout("Press any key to exit...");
        System.in.read();

        Pool.clear(poolHandle);
        sout("Cleared Pool " + poolHandle);

        sout("Exiting..." + getClass().getName());
    }

    public static void main(String[] args) throws Exception {
        ShmWriter shmWriter = new ShmWriter();

        InputStream is = ShmWriter.class.getClassLoader().getResourceAsStream("shm-writer.properties");
        Properties properties = new Properties();
        properties.load(is);
        sout("Using properties:");
        sout(properties.toString());

        shmWriter.test(properties);
    }
}
